Skip to content

Update SAML documentation#1084

Open
maartenba wants to merge 10 commits into
release/is-v8.0from
v8-saml
Open

Update SAML documentation#1084
maartenba wants to merge 10 commits into
release/is-v8.0from
v8-saml

Conversation

@maartenba
Copy link
Copy Markdown
Member

@maartenba maartenba commented May 5, 2026

May 15, 2026 / 2249a0935853b79a8453f1baab979f21b4b7255e

khalidabuhakmeh and others added 4 commits April 28, 2026 20:27
…pgrade guide (#1080)

* Add changes from products repository (PR 255 and 256), optimize for readability in docs site

* Reorganize IdentityServer upgrade guide overview for improved clarity and consistency

* Add IdentityServer4 to Duende IdentityServer v8.0 upgrade guide detailing migration steps, breaking changes, and schema updates.
@maartenba maartenba self-assigned this May 5, 2026
@maartenba maartenba added the documentation Improvements or additions to documentation label May 5, 2026
@maartenba maartenba changed the base branch from main to release/is-v8.0 May 5, 2026 10:16
@maartenba maartenba added this to the 2026-Q2 milestone May 5, 2026
@maartenba maartenba marked this pull request as ready for review May 5, 2026 10:36
Comment thread astro/src/content/docs/identityserver/saml/concepts.md
Comment thread astro/src/content/docs/identityserver/saml/concepts.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/concepts.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/configuration.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/configuration.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/endpoints.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/extensibility.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/extensibility.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/extensibility.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/index.md
@khalidabuhakmeh
Copy link
Copy Markdown
Contributor

@maartenba the SAML 2.0 Concepts page was meant to be a general overview of SAML (with maybe some light linking into our implementation). Not sure if adding code blocks and implementation details is right for that page.

Comment thread astro/src/content/docs/identityserver/saml/concepts.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/configuration.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/configuration.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/configuration.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/configuration.md
…ards-compat language, add mermaid diagrams for SP-initiated SSO and SLO flows, code-block protocol terms in prose, fix ambiguous pronouns
@maartenba
Copy link
Copy Markdown
Member Author

Addressed review feedback in 21c08bf:

  • Removed InCommon example from concepts.md
  • Trimmed IdentityServer-specific content on the concepts page (kept brief cross-links)
  • Removed all "backwards compatibility" language (this is a new package, no prior version)
  • Removed "(not an enum)" from SamlEndpointType
  • Changed "request ages" → "request lifetimes"
  • Fixed ambiguous "it" in endpoints.md SLO note
  • Code-blocked AuthnRequest, AuthnContext, and NameID everywhere in extensibility.md prose
  • Added mermaid sequence diagrams for SP-initiated SSO flow and Single Logout flow
  • Reviewed "What's Included" section — looks comprehensive, no changes needed

Not addressed (not a docs change): __Host- cookie prefix implementation question (item 11)

Comment thread astro/src/content/docs/identityserver/saml/extensibility.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/extensibility.md Outdated
…ed envs, correct reasons are size limits, client exposure, and auditability
Comment thread astro/src/content/docs/identityserver/saml/concepts.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/concepts.md
Comment thread astro/src/content/docs/identityserver/saml/configuration.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/configuration.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/configuration.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/extensibility.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/index.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/index.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/index.md Outdated
Comment thread astro/src/content/docs/identityserver/saml/service-providers.md Outdated
…ceProviderAdmin, ServiceProviderEntityId, encryption), fix NameID formats (email+unspecified only), correct ISamlSigninStateStore (in-memory default, EF for prod), rename ISamlSigninInteractionResponseGenerator, update ISamlInteractionService deprecation, add EF Core store docs
@maartenba
Copy link
Copy Markdown
Member Author

Addressed bhazen's review feedback in c9d2d9b:

Removed (platform-only / not in v8):

  • ISamlServiceProviderAdmin — entire section + all references
  • ServiceProviderEntityId value object — replaced with plain string
  • SigninStateCookieName — property being removed from code
  • Encryption section (not making v1)
  • EncryptionCertificates, EncryptAssertions properties
  • RequireConsent (consent doesn't exist in SAML)
  • ISamlFrontChannelLogout section (going away)
  • Obsolete AssertionConsumerServiceBinding

Fixed:

  • ISamlSigninInteractionResponseGeneratorISaml2SsoInteractionResponseGenerator (no consent)
  • ISamlInteractionService — added deprecation note, describes GetAuthenticationContextAsync pattern
  • ISamlSigninStateStore — default is in-memory (not cookie), EF for production
  • ISamlNameIdGenerator — only email + unspecified (no persistent for v1)
  • NameID formats — clarified only email/unspecified supported, persistent planned
  • Login Page Compatibility — removed IAuthenticationContext, describes returnUrl + GetAuthenticationContextAsync
  • Saml2Options.EntityId — most deployments don't need to set it, default is {host}/saml
  • AllowedScopes — simplified description per bhazen's note

Added:

  • EF Core store documentation (Duende.IdentityServer.EntityFramework.Stores) in service-providers.md and index.md

The Identity Provider signs the assertion with its private key. The Service Provider validates the signature before trusting any claims inside. IdentityServer builds assertions automatically when it processes a SAML sign-in request. You control what attributes appear in assertions via claim mappings — see [`SamlOptions.DefaultClaimMappings` and `SamlServiceProvider.ClaimMappings`](/identityserver/saml/configuration.md#default-claim-mappings). The signing behavior is configured via the [`SamlSigningBehavior` enum](/identityserver/saml/configuration.md#samlsigningbehavior).
The Identity Provider signs the assertion with its private key. The Service Provider validates the signature before trusting any claims inside.

In IdentityServer, you control what attributes appear in assertions via [claim mappings](/identityserver/saml/configuration.md#default-claim-mappings) and configure signing via [`SamlSigningBehavior`](/identityserver/saml/configuration.md#samlsigningbehavior).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bit more to what controls which attributes appear in the assertions. There's a few relevant settings on the Service Provider:

  1. AllowedScopes - controls which claims can be requested by a service provider by which scopes are allowed here. These should be identity resources which contain the appropriate scopes.
  2. RequestedClaimTypes - default claim types to request

If RequestedClaimTypes is not set, all claim types resolved from AllowedScopes will be used. RequestedClaimTypes is a way to set the claims to a default subset of AllowedScopes.

The intent was to set this up such that someday we could support Attribute Consuming Services from Authn requests.

The claim mappings then map any of the claims from the OIDC claim name to whatever is in the mapping.

Metadata makes federation scalable. Instead of manually exchanging certificates and endpoint URLs out-of-band, parties import each other's metadata and configure trust automatically. Large identity federations — such as InCommon (over 1,000 organizations) — rely on machine-readable metadata to coordinate trust across hundreds or thousands of participants.
Metadata makes federation scalable. Instead of manually exchanging certificates and endpoint URLs out-of-band, parties import each other's metadata and configure trust automatically.

IdentityServer publishes its IdP metadata at `/saml/metadata`. Share this URL with each Service Provider during federation setup so they can automatically discover your signing certificates, NameID formats, and endpoint locations. See the [metadata endpoint](/identityserver/saml/endpoints.md#metadata-endpoint) for more details.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SAML metadata is published to the EntityId of IdentityServer when acting as an IdP to be compliant with the SAML metadata spec. By default that's /Saml2. This can be be modified by a couple different properties on SamlOptions:

  1. Changing the EntityIdPath setting which defaults to /Saml2 (i.e. changing it to foo would make the metadata route /foo
  2. Changing the EntityId which makes the metadata route whatever the path of the value for EntityId is if it http or https url


### Front-Channel Logout

IdentityServer uses front-channel logout, which means logout notifications travel through the user's browser via redirects. The IdP redirects the browser to each SP's SLO endpoint in sequence, and each SP terminates its local session before the browser is redirected onward. This approach is simpler to implement than back-channel (server-to-server) logout, but it requires the user's browser to remain open and active throughout the logout sequence. Back-channel logout is not supported.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what the spec describes, but it's not how we implemented it. Rather than the redirect chain, we're using iframes. It is not spec compliant, but it prevents the entire processing from failing if one SP does not respond and ends up being a bit less brittle. So we render all the iframes on the same page as where we do for OIDC and record responses if we receive them to generate a proper final status.

### Timeouts and Edge Cases

For this reason, many deployments supplement SLO — or replace it entirely — with short session lifetimes and per-application logout as a simpler fallback.
If an SP is unreachable or the user closes the browser mid-flow, the logout sequence may not complete for all SPs. Short session lifetimes and per-application logout are common supplements to SLO in deployments where reliability matters more than protocol completeness. You can tune logout timeout behavior via `SamlOptions` to balance user experience against thoroughness.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This option controls the TTL for records in the ISamlLogoutSessionStore, but a bigger factor may be how long the user waits on the page where the iframes are rendered. If the user clicks off of that before all the SPs in the session respond, it will result in a status as if the logout sequence didn't complete. Maybe it's worth including something about that here.

For this reason, many deployments supplement SLO — or replace it entirely — with short session lifetimes and per-application logout as a simpler fallback.
If an SP is unreachable or the user closes the browser mid-flow, the logout sequence may not complete for all SPs. Short session lifetimes and per-application logout are common supplements to SLO in deployments where reliability matters more than protocol completeness. You can tune logout timeout behavior via `SamlOptions` to balance user experience against thoroughness.

In IdentityServer, you configure SLO per SP by setting `SamlServiceProvider.SingleLogoutServiceUrl`. IdentityServer then sends front-channel logout notifications to all SPs with a configured SLO endpoint when a user's session ends. See the [logout endpoint](/identityserver/saml/endpoints.md#logout-endpoint) and [`ISamlLogoutNotificationService`](/identityserver/saml/extensibility.md#isamllogoutnotificationservice) for customization options.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now we only support the HttpRedirect binding for SLO as that restriction alleviated some potential issues for us. It is probably worth calling that out here.

## ISaml2MetadataResponseGenerator

`ISaml2MetadataResponseGenerator` generates the IdP metadata document served at the
`/saml/metadata` endpoint. SAML metadata describes the IdP's capabilities, endpoints, and signing
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`/saml/metadata` endpoint. SAML metadata describes the IdP's capabilities, endpoints, and signing
`/Saml2` endpoint. SAML metadata describes the IdP's capabilities, endpoints, and signing

### 1. Register SAML Services

Call `AddSaml()` on the IdentityServer builder:
Call `AddSaml()` on the IdentityServer builder to enable all SAML endpoints (IdP-initiated SSO requires explicit opt-in):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Call `AddSaml()` on the IdentityServer builder to enable all SAML endpoints (IdP-initiated SSO requires explicit opt-in):
Call `AddSaml()` on the IdentityServer builder to enable all SAML endpoints:


## Protocol Endpoints

SAML 2.0 endpoints are registered under the `/saml` path prefix:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SAML 2.0 endpoints are registered under the `/Saml2` path prefix:

Comment on lines 112 to 119
| Endpoint | Path |
| ----------------- | ----------------------- |
| Metadata | `/saml/metadata` |
| Sign-in | `/saml/signin` |
| Sign-in Callback | `/saml/signin_callback` |
| IdP-initiated SSO | `/saml/idp-initiated` |
| Logout | `/saml/logout` |
| Logout Callback | `/saml/logout_callback` |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| Logout Callback | `/saml/logout_callback` |
| Endpoint | Path |
| ----------------- | ----------------------- |
| Metadata | `/Saml2` |
| Sign-in | `/Saml2/SSO` |
| Sign-in Callback | `/Saml2/SSO/Callback` |
| Logout | `/Saml2/SLO` |
| Logout Callback | `/Saml2/SLO/Callback` |

The migration creates five new tables in the configuration database: `SamlServiceProviders`,
`SamlServiceProviderAssertionConsumerServices`, `SamlServiceProviderSigningCertificates`,
`SamlServiceProviderEncryptionCertificates`, and `SamlServiceProviderClaimMappings`.
The migration creates several new tables in the configuration database: `SamlServiceProviders`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are new tables for operational data for SAML for sign-in and logout too. As of the time of writing this comment, the PR that adds the logout tables is still open.

@bhazen
Copy link
Copy Markdown
Contributor

bhazen commented May 15, 2026

Additional review findings

Cross-referenced the docs against the current source code. These are issues not already covered by existing review comments.


configuration.md

  1. SamlEndpointType.Location is string, not Uri — The IndexedEndpoint code examples use Location = new Uri("https://sp.example.com/acs") but the actual property type is string. Should be Location = "https://sp.example.com/acs". This also affects service-providers.md and index.md (every SP config example).

  2. DisplayName shown as "Required" — The property is string? (nullable) and nothing enforces it. Should be listed as optional.

  3. IndexedEndpoint.IsDefault shown as bool? — The actual type is bool (non-nullable).

  4. AuthnContextMappings type shown as Dictionary<string, string> — The actual type is IDictionary<string, string>.

  5. EmailNameIdClaimType "defaults to ClaimTypes.Email" — The actual default is the string "email", which is a different value than ClaimTypes.Email (http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress).


service-providers.md

  1. AddSamlConfigurationStore() does not exist — The EF Core store registration section documents a non-existent extension method. The correct method is AddConfigurationStore(...).

  2. ClaimMappings = new ReadOnlyDictionary<string, string>(...) — The full config example won't compile. The property type is IDictionary<string, string>, so this should be new Dictionary<string, string>.

  3. Location = new Uri(...) in all SP config examples — Same as finding Re-work reference section #1 above.


index.md

  1. Location = new Uri(...) in the Quick Setup SP example — Same as finding Re-work reference section #1.

extensibility.md

  1. Default ISamlLogoutNotificationService is a no-op — The docs describe the default as sending LogoutRequests to SPs. The actual default registered in DI is NopSamlLogoutNotificationService, which does nothing. The real Saml2LogoutNotificationService is not the default.

  2. IIdpInitiatedSsoService example calls result.ToActionResult() — This method doesn't exist on IdpInitiatedSsoResult.

  3. StatusCodes.Responder / StatusCodes.UnknownPrincipal in the ISamlNameIdGenerator example — No namespace/using shown. Could easily be confused with Microsoft.AspNetCore.Http.StatusCodes. Worth adding a comment or using the fully qualified name.

  4. Interface signatures show CancellationToken ct = default — The actual interfaces use Ct ct (no default). Affects ISaml2SsoInteractionResponseGenerator, ISaml2SsoResponseGenerator, ISaml2SloResponseGenerator, IAuthnRequestValidator, ILogoutRequestValidator, ISaml2FrontChannelLogoutRequestBuilder. Not a compile error for implementers but the shown signatures don't match the source.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants